* @param $context IContextSource context to use to get the messages
* @param $namespace int Namespace number
* @param $title string Text of the title, without the namespace part
+ * @return string
*/
public static function getInvalidTitleDescription( IContextSource $context, $namespace, $title ) {
global $wgContLang;
if ( !$thumb ) {
$s = self::makeBrokenImageLinkObj( $title, $fp['title'], '', '', '', $time == true );
} else {
+ self::processResponsiveImages( $file, $thumb, $hp );
$params = array(
'alt' => $fp['alt'],
'title' => $fp['title'],
$hp['width'] = isset( $fp['upright'] ) ? 130 : 180;
}
$thumb = false;
+ $noscale = false;
if ( !$exists ) {
$outerWidth = $hp['width'] + 2;
} elseif ( isset( $fp['framed'] ) ) {
// Use image dimensions, don't scale
$thumb = $file->getUnscaledThumb( $hp );
+ $noscale = true;
} else {
# Do not present an image bigger than the source, for bitmap-style images
# This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour
$s .= wfMessage( 'thumbnail_error', '' )->escaped();
$zoomIcon = '';
} else {
+ if ( !$noscale ) {
+ self::processResponsiveImages( $file, $thumb, $hp );
+ }
$params = array(
'alt' => $fp['alt'],
'title' => $fp['title'],
return str_replace( "\n", ' ', $s );
}
+ /**
+ * Process responsive images: add 1.5x and 2x subimages to the thumbnail, where
+ * applicable.
+ *
+ * @param File $file
+ * @param MediaOutput $thumb
+ * @param array $hp image parameters
+ */
+ protected static function processResponsiveImages( $file, $thumb, $hp ) {
+ global $wgResponsiveImages;
+ if ( $wgResponsiveImages ) {
+ $hp15 = $hp;
+ $hp15['width'] = round( $hp['width'] * 1.5 );
+ $hp20 = $hp;
+ $hp20['width'] = $hp['width'] * 2;
+ if ( isset( $hp['height'] ) ) {
+ $hp15['height'] = round( $hp['height'] * 1.5 );
+ $hp20['height'] = $hp['height'] * 2;
+ }
+
+ $thumb15 = $file->transform( $hp15 );
+ $thumb20 = $file->transform( $hp20 );
+ if ( $thumb15->url !== $thumb->url ) {
+ $thumb->responsiveUrls['1.5'] = $thumb15->url;
+ }
+ if ( $thumb20->url !== $thumb->url ) {
+ $thumb->responsiveUrls['2'] = $thumb20->url;
+ }
+ }
+ }
+
/**
* Make a "broken" link to an image
*
// check if the user has an edit
$attribs = array();
if ( $redContribsWhenNoEdits ) {
- $count = !is_null( $edits ) ? $edits : User::edits( $userId );
- if ( $count == 0 ) {
+ if ( intval( $edits ) === 0 && $edits !== 0 ) {
+ $user = User::newFromId( $userId );
+ $edits = $user->getEditCount();
+ }
+ if ( $edits === 0 ) {
$attribs['class'] = 'new';
}
}
* - 'usable' Valid for batch processes and login
* - 'creatable' Valid for batch processes, login and account creation
*
+ * @throws MWException
* @return bool|string
*/
public static function getCanonicalName( $name, $validate = 'valid' ) {
/**
* Count the number of edits of a user
- * @todo It should not be static and some day should be merged as proper member function / deprecated -- domas
*
* @param $uid Int User ID to check
* @return Int the user's edit count
+ *
+ * @deprecated since 1.21 in favour of User::getEditCount
*/
public static function edits( $uid ) {
- wfProfileIn( __METHOD__ );
- $dbr = wfGetDB( DB_SLAVE );
- // check if the user_editcount field has been initialized
- $field = $dbr->selectField(
- 'user', 'user_editcount',
- array( 'user_id' => $uid ),
- __METHOD__
- );
-
- if( $field === null ) { // it has not been initialized. do so.
- $dbw = wfGetDB( DB_MASTER );
- $count = $dbr->selectField(
- 'revision', 'count(*)',
- array( 'rev_user' => $uid ),
- __METHOD__
- );
- $dbw->update(
- 'user',
- array( 'user_editcount' => $count ),
- array( 'user_id' => $uid ),
- __METHOD__
- );
- } else {
- $count = $field;
- }
- wfProfileOut( __METHOD__ );
- return $count;
+ wfDeprecated( __METHOD__, '1.21' );
+ $user = self::newFromId( $uid );
+ return $user->getEditCount();
}
/**
if( $loggedOut !== null ) {
$this->mTouched = wfTimestamp( TS_MW, $loggedOut );
} else {
- $this->mTouched = '0'; # Allow any pages to be cached
+ $this->mTouched = '1'; # Allow any pages to be cached
}
$this->mToken = null; // Don't run cryptographic functions till we need a token
$this->mEffectiveGroups = null;
$this->mImplicitGroups = null;
$this->mOptions = null;
+ $this->mEditCount = null;
if ( $reloadFrom ) {
$this->mLoadedItems = array();
$defOpt = $wgDefaultUserOptions;
# default language setting
- $variant = $wgContLang->getDefaultVariant();
- $defOpt['variant'] = $variant;
- $defOpt['language'] = $variant;
+ $defOpt['variant'] = $wgContLang->getCode();
+ $defOpt['language'] = $wgContLang->getCode();
foreach( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
$defOpt['searchNs'.$nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
}
if( $this->getId() ) {
if ( !isset( $this->mEditCount ) ) {
/* Populate the count, if it has not been populated yet */
- $this->mEditCount = User::edits( $this->mId );
+ wfProfileIn( __METHOD__ );
+ $dbr = wfGetDB( DB_SLAVE );
+ // check if the user_editcount field has been initialized
+ $count = $dbr->selectField(
+ 'user', 'user_editcount',
+ array( 'user_id' => $this->mId ),
+ __METHOD__
+ );
+
+ if( $count === null ) {
+ // it has not been initialized. do so.
+ $dbw = wfGetDB( DB_MASTER );
+ $count = $dbr->selectField(
+ 'revision', 'count(*)',
+ array( 'rev_user' => $this->mId ),
+ __METHOD__
+ );
+ $dbw->update(
+ 'user',
+ array( 'user_editcount' => $count ),
+ array( 'user_id' => $this->mId ),
+ __METHOD__
+ );
+ }
+ wfProfileOut( __METHOD__ );
+ $this->mEditCount = $count;
}
return $this->mEditCount;
} else {
}
/**
- * Add this existing user object to the database
+ * Add this existing user object to the database. If the user already
+ * exists, a fatal status object is returned, and the user object is
+ * initialised with the data from the database.
+ *
+ * Previously, this function generated a DB error due to a key conflict
+ * if the user already existed. Many extension callers use this function
+ * in code along the lines of:
+ *
+ * $user = User::newFromName( $name );
+ * if ( !$user->isLoggedIn() ) {
+ * $user->addToDatabase();
+ * }
+ * // do something with $user...
+ *
+ * However, this was vulnerable to a race condition (bug 16020). By
+ * initialising the user object if the user exists, we aim to support this
+ * calling sequence as far as possible.
+ *
+ * Note that if the user exists, this function will acquire a write lock,
+ * so it is still advisable to make the call conditional on isLoggedIn(),
+ * and to commit the transaction after calling.
+ *
+ * @return Status
*/
public function addToDatabase() {
$this->load();
'user_registration' => $dbw->timestamp( $this->mRegistration ),
'user_editcount' => 0,
'user_touched' => $dbw->timestamp( $this->mTouched ),
- ), __METHOD__
+ ), __METHOD__,
+ array( 'IGNORE' )
);
+ if ( !$dbw->affectedRows() ) {
+ $this->mId = $dbw->selectField( 'user', 'user_id',
+ array( 'user_name' => $this->mName ), __METHOD__ );
+ $loaded = false;
+ if ( $this->mId ) {
+ if ( $this->loadFromDatabase() ) {
+ $loaded = true;
+ }
+ }
+ if ( !$loaded ) {
+ throw new MWException( __METHOD__. ": hit a key conflict attempting " .
+ "to insert a user row, but then it doesn't exist when we select it!" );
+ }
+ return Status::newFatal( 'userexists' );
+ }
$this->mId = $dbw->insertId();
// Clear instance cache other than user table data, which is already accurate
$this->clearInstanceCache();
$this->saveOptions();
+ return Status::newGood();
}
/**
public static function getGroupsWithPermission( $role ) {
global $wgGroupPermissions;
$allowedGroups = array();
- foreach ( $wgGroupPermissions as $group => $rights ) {
- if ( isset( $rights[$role] ) && $rights[$role] ) {
+ foreach ( array_keys( $wgGroupPermissions ) as $group ) {
+ if ( self::groupHasPermission( $group, $role ) ) {
$allowedGroups[] = $group;
}
}
return $allowedGroups;
}
+ /**
+ * Check, if the given group has the given permission
+ *
+ * @param $group String Group to check
+ * @param $role String Role to check
+ * @return bool
+ */
+ public static function groupHasPermission( $group, $role ) {
+ global $wgGroupPermissions, $wgRevokePermissions;
+ return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
+ && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
+ }
+
/**
* Get the localized descriptive name for a group, if it exists
*
* @todo document
*/
protected function loadOptions() {
+ global $wgContLang;
+
$this->load();
- if ( $this->mOptionsLoaded || !$this->getId() )
+
+ if ( $this->mOptionsLoaded ) {
return;
+ }
$this->mOptions = self::getDefaultOptions();
+ if ( !$this->getId() ) {
+ // For unlogged-in users, load language/variant options from request.
+ // There's no need to do it for logged-in users: they can set preferences,
+ // and handling of page content is done by $pageLang->getPreferredVariant() and such,
+ // so don't override user's choice (especially when the user chooses site default).
+ $variant = $wgContLang->getDefaultVariant();
+ $this->mOptions['variant'] = $variant;
+ $this->mOptions['language'] = $variant;
+ $this->mOptionsLoaded = true;
+ return;
+ }
+
// Maybe load from the object
if ( !is_null( $this->mOptionOverrides ) ) {
wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );